package com.rytx.common.core.redis;

import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Service
public class RedisQueueService<T> {

    @Resource
    private RedisTemplate<String, T> redisTemplate;

    public Long enqueue(String queueName, T message) {        // 判断RedisTemplate是否已初始化
        if (redisTemplate == null) {
            throw new IllegalStateException("RedisTemplate 尚未初始化。");
        }
        // 判断队列名是否为空或空字符串
        if (queueName == null || queueName.isEmpty()) {
            throw new IllegalArgumentException("队列名称不能为 null 或为空。");
        }
        // 判断消息是否为空
        if (message == null) {
            throw new IllegalArgumentException("消息不能为 null");
        }
        // 获取List操作对象
        ListOperations<String, T> listOps = redisTemplate.opsForList();
        // 将消息入队到指定队列的右侧
       return listOps.rightPush(queueName, message);
    }

    public T dequeue(String queueName) {
        // 判断 RedisTemplate 是否为空
        if (redisTemplate == null) {
            // 抛出异常，提示 RedisTemplate 未初始化
            throw new IllegalStateException("RedisTemplate 尚未初始化。");
        }
        // 获取 Redis 列表操作对象
        ListOperations<String, T> listOps = redisTemplate.opsForList();
        // 从指定队列中移除并返回第一个元素
        return listOps.leftPop(queueName);
    }

    // 如果需要阻塞式出队，可以使用 BRPOP 命令的封装方法
    public T blockingDequeue(String queueName, long timeout) {
        // 检查 RedisTemplate 是否为空
        if (redisTemplate == null) {
            // 如果 RedisTemplate 为空，则抛出异常
            throw new IllegalStateException("RedisTemplate 尚未初始化。");
        }
        // 获取 List 类型的 Redis 操作对象
        ListOperations<String, T> listOps = redisTemplate.opsForList();
        // 使用 rightPopAndLeftPush 方法实现阻塞式出队，并将弹出的元素推入到另一个队列 "blocking-" + queueName
        // timeout 表示阻塞超时时间，单位为秒
        return listOps.rightPopAndLeftPush(queueName, "blocking-" + queueName, timeout, TimeUnit.SECONDS);
    }
}